package common;

import java.sql.ResultSet;
import java.util.*;

import javax.servlet.http.HttpServletRequest;

public class CheckUser {
	private HttpServletRequest request;
	public String companyCodeTsn = "2";

	public CheckUser(HttpServletRequest req, String companyCode) {
		this.request = req;
		this.companyCodeTsn = companyCode;
	}

	/**
	 * 精確檢查. (or 處理, 只要有一個工號在裡面 就是有權限)
	 * 
	 * @param item
	 *            String[]
	 * @param terms
	 *            String[]
	 * @return boolean
	 */
	private boolean exactCheck(String[] item, String exact) {
		boolean result = false;
		exact = (exact == null) ? "" : exact;
		String[] terms = exact.split(",");
		for (int i = 0; i < terms.length; i++) {
			if (item[0].trim().equalsIgnoreCase(terms[i].trim())) {
				result = true;
				break;
			}
		}
		return result;
	}

	/**
	 * 模糊檢查. (or 處理, 只有符合一組關鍵字 就是有權限)
	 * 
	 * @param item
	 *            String[]
	 * @param terms
	 *            String[]
	 * @return boolean
	 */
	private boolean fuzzyCheck(String[] item, String fuzzy) {
		boolean result = false;
		fuzzy = (fuzzy == null) ? "" : fuzzy;
		String[] terms = fuzzy.split(",");
		for (int i = 0; i < terms.length; i++) {
			if (this.fuzzyCheck(item[2] + ", " + item[3], terms[i])) {
				result = true;
				break;
			}
		}
		return result;
	}

	/**
	 * 模糊檢查. (and 處理, fuzzy 裡面的字 要全部出現在 item 裡面 才算有權限)
	 * 
	 * @param item
	 *            String
	 * @param fuzzy
	 *            String
	 * @return boolean
	 */
	private boolean fuzzyCheck(String item, String fuzzy) {
		boolean result = true;
		String[] terms = fuzzy.split("\\+");
		for (int i = 0; i < terms.length; i++) {
			String term = terms[i].trim().toLowerCase();
			// 如果前後有使用 [] 包起來, 要使用 equals判斷, 最後一個 逗號(, )後面那串字的內容.
			if (term.startsWith("[") && term.endsWith("]")) {
				String[] items = item.split(", ");
				if (!items[items.length - 1].equalsIgnoreCase(term.substring(1,
						term.length() - 1))) {
					result = false;
					break;
				}
			} else { // 否則使用 contains 判斷, 如果不包含 就是 false.
				if (!item.trim().toLowerCase().contains(
						terms[i].trim().toLowerCase())) {
					result = false;
					break;
				}
			}
		}
		return result;
	}

	/**
	 * 取得 帳號檔裡面 所有帳號的完整部門名稱.
	 * 
	 * @return List
	 * @throws Exception
	 */
	private List getAccountList() throws Exception {
		Utils utils = new Utils(request);
		CommonType common = new CommonType(utils);
		Map parentMap = common.roleTsn(); // 組織 子階與父階 map.
		Map deptNameMap = common.orgTitleSn(companyCodeTsn); // 組織Tsn 換 組織名稱
																// map.
		Map bufferMap = new HashMap(); // 暫存的 map.
		String sql = "select hrNum, chName, isnull(titleName, '') as titleName, hr003Tsn from hr..hr006 a left join hr..hr005 b on a.hr005tsn = b.tsn left join hr..hr002 c on b.hr002tsn = c.tsn where a.defau=1 and b.leaveday = '' order by hr003tsn";
		ResultSet rs = utils.executeQuery("info3", sql);
		List<String[]> list = new ArrayList<String[]>();
		while (rs.next()) {
			String[] temp = new String[4];
			temp[0] = rs.getString("hrNum"); // 工號
			temp[1] = rs.getString("chName"); // 姓名
			temp[2] = rs.getString("titleName"); // 職稱
			temp[3] = this.getFullDeptName(rs.getString("hr003Tsn"), bufferMap,
					parentMap, deptNameMap);
			list.add(temp);
		}
		utils.cleanUp();
		return list;
	}

	/**
	 * 取得某部門的完整名稱.
	 * 
	 * @param deptTsn
	 *            String
	 * @param bufferMap
	 *            Map
	 * @param parentMap
	 *            Map
	 * @param deptNameMap
	 *            Map
	 * @return String
	 */
	private String getFullDeptName(String deptTsn, Map bufferMap,
			Map parentMap, Map deptNameMap) {
		String result = null;
		if (bufferMap.get(deptTsn) != null) { // 如果bufferMap裡面有這部門 就直接取得.
			result = (String) bufferMap.get(deptTsn);
		} else {
			result = this.getFullDeptTsn(deptTsn, parentMap);
			result = this.changeTsn2Name(result, deptNameMap);
			bufferMap.put(deptTsn, result);
		}
		return result;
	}

	/**
	 * 取得某部門的完整Tsn.
	 * 
	 * @param tsn
	 *            String
	 * @param parentMap
	 *            Map
	 * @return String
	 */
	private String getFullDeptTsn(String tsn, Map parentMap) {
		String[] ary = tsn.split(":");
		if (parentMap.get(ary[0]) != null) {
			tsn = parentMap.get(ary[0]) + ":" + tsn;
			tsn = this.getFullDeptTsn(tsn, parentMap);
		}
		return tsn;
	}

	/**
	 * 部門Tsn -> 部門名稱.
	 * 
	 * @param fullTsn
	 *            String
	 * @param deptNameMap
	 *            Map
	 * @return String
	 */
	private String changeTsn2Name(String fullTsn, Map deptNameMap) {
		String fullName = "";
		if (fullTsn != null) {
			String[] ary = fullTsn.split(":");
			for (int i = 0; i < ary.length; i++) {
				fullName += ", " + (String) deptNameMap.get(ary[i]);
			}
		}
		return fullName.replaceFirst(", null, ", "");
	}

	/**
	 * 取得 某工號的 完整部門名稱資料.
	 * 
	 * @param hrNum
	 *            String
	 * @return String[]
	 * @throws Exception
	 */
	private String[] getAccountData(String hrNum) throws Exception {
		String[] result = new String[4];
		Utils utils = new Utils(request);
		CommonType common = new CommonType(utils);
		Map parentMap = common.roleTsn(); // 組織 子階與父階 map.
		Map deptNameMap = common.orgTitleSn(companyCodeTsn); // 組織Tsn 換 組織名稱
																// map.
		Map bufferMap = new HashMap(); // 暫存的 map.
		String sql = "select hrNum, chName, isnull(titleName, '') as titleName, hr003Tsn from hr..hr006 a left join hr..hr005 b on a.hr005tsn = b.tsn left join hr..hr002 c on b.hr002tsn = c.tsn where a.defau=1 and hrNum = '"
				+ hrNum + "'  and b.leaveday = '' ";
		ResultSet rs = utils.executeQuery("info3", sql);
		if (rs.next()) {
			result[0] = rs.getString("hrNum"); // 工號
			result[1] = rs.getString("chName"); // 姓名
			result[2] = rs.getString("titleName"); // 職稱
			result[3] = this.getFullDeptName(rs.getString("hr003Tsn"),
					bufferMap, parentMap, deptNameMap);
		}
		utils.cleanUp();
		return result;
	}

	/**
	 * [sys002a] 裡面的使用者 可以有所有權限.
	 * 
	 * @param hrNum
	 * @return
	 * @throws Exception
	 */
	private boolean isPowerUser(String hrNum) throws Exception {
		boolean result = false;
		Utils utils = new Utils(request);
		String sql = "select * from sys..sys002a where enab = '1' and hrnum = ?";
		utils.prepareStatement("sqltest", sql);
		utils.setString(1, hrNum);
		ResultSet rs = utils.executeQuery();
		result = rs.next();
        utils.cleanUp();
		return result;
	}
	
	/**
	 * @param hrnum
	 * @return
	 * @author yanjie
	 */
	private boolean isPowerUserNew(String hrnum) throws Exception{
		if(getPowerUserList(false) == null || getPowerUserList(false).size() == 0 || hrnum == null)
			return false ;
		else
			return getPowerUserList(false).contains(hrnum);
	}
	
	private static List powerUserList ; // 超級用戶列表
	/**
	 * @return
	 * @throws Exception
	 * @author yanjie
	 */
	private List getPowerUserList(boolean isUpdate) throws Exception {
		if(powerUserList == null || isUpdate){
			powerUserList = new ArrayList();
			Utils utils = new Utils(request);
			String sql = "select hrnum from sys..sys002a where enab = '1' ";
			utils.prepareStatement("sqltest", sql);
			ResultSet rs = utils.executeQuery();
			while(rs.next()){
				powerUserList.add(rs.getString("hrnum"));
			}
			rs.close();
			utils.cleanUp();
		}
		
		return powerUserList ;
	}
	
	private static List<Map<String,String>> allMenuList ;
	/**
	 * @return
	 * @author yanjie
	 */
	private List<Map<String,String>> getAllMenuList(boolean isUpdate) throws Exception{
		if(allMenuList == null || isUpdate){
			Utils utils = new Utils(request);
			allMenuList = new ArrayList<Map<String,String>>();
			
			String sql = "select a.tsn,a.ftsn,a.nam,a.url,a.srt,b.staffSet,b.orgSet from sys..sys001 a left join sys..sys002 b on a.sys002tsn = b.tsn where enab = '1' order by a.srt";
			ResultSet rs = utils.executeQuery("sqltest", sql);
			while (rs.next()) {
				Map map = new HashMap();
				map.put("tsn",rs.getString("tsn"));
				map.put("ftsn",rs.getString("ftsn"));
				map.put("nam",rs.getString("nam"));
				map.put("url",rs.getString("url"));
				map.put("srt",rs.getString("srt"));
				map.put("staffSet",rs.getString("staffSet"));
				map.put("orgSet",rs.getString("orgSet"));
				allMenuList.add(map);
			}
			rs.close();
			utils.cleanUp();
		}
		
		return allMenuList;
	}
	
	public void deployMenu() throws Exception{
		getPowerUserList(true);
		getAllMenuList(true);
	}
	
	/**
	 * @param hrNum
	 * @return
	 * @throws Exception
	 * @author yanjie
	 */
	public List getMenuListNew(String hrNum) throws Exception {
		List<String[]> result = new ArrayList<String[]>();
		Utils utils = new Utils(request);
		String[] data = this.getAccountData(hrNum);
		boolean isPowerUser = this.isPowerUserNew(hrNum); // 如果有, 表示可以看到所有menu.
		// 找出所有的 Menu List.
		
		for (Iterator iter = getAllMenuList(false).iterator(); iter.hasNext();) {
			Map<String,String> rs = (Map<String,String>) iter.next();
			if (isPowerUser) {
				String[] temp = new String[5];
				temp[0] = rs.get("tsn"); // 選單 tsn
				temp[1] = rs.get("ftsn"); // 父階選單 tsn
				temp[2] = rs.get("nam"); // 選單名稱
				temp[3] = rs.get("url"); // 選單 url
                temp[4] = rs.get("srt"); // 選單編號
				result.add(temp);
			} else {
				String exact = rs.get("staffSet"); // exact value.
				String fuzzy = rs.get("orgSet"); // fuzzy value.
				
				// 檢查是否符合條件, 是的話 新增到 result 裡面.
				if ((fuzzy == null && exact == null)
						|| (exact != null && this.exactCheck(data, exact))
						|| (fuzzy != null && fuzzy.trim().length() != 0 && this
								.fuzzyCheck(data, fuzzy))) {
					String[] temp = new String[5];
					temp[0] = rs.get("tsn"); // 選單 tsn
					temp[1] = rs.get("ftsn"); // 父階選單 tsn
					temp[2] = rs.get("nam"); // 選單名稱
					temp[3] = rs.get("url"); // 選單 url
                    temp[4] = rs.get("srt"); // 選單編號
					result.add(temp);
				}
			}
		}
		
		utils.cleanUp();
		return result;
	}
	

	public List getMenuList(String hrNum) throws Exception {
		List<String[]> result = new ArrayList<String[]>();
		Utils utils = new Utils(request);
		String[] data = this.getAccountData(hrNum);
		boolean isPowerUser = this.isPowerUser(hrNum); // 如果有, 表示可以看到所有menu.
		// 找出所有的 Menu List.
		String sql = "select a.tsn,a.ftsn,a.nam,a.url,a.srt,b.staffSet,b.orgSet from sys..sys001 a left join sys..sys002 b on a.sys002tsn = b.tsn where enab = '1' order by a.srt";
		ResultSet rs = utils.executeQuery("sqltest", sql);
		while (rs.next()) {
			if (isPowerUser) {
				String[] temp = new String[5];
				temp[0] = rs.getString("tsn"); // 選單 tsn
				temp[1] = rs.getString("ftsn"); // 父階選單 tsn
				temp[2] = rs.getString("nam"); // 選單名稱
				temp[3] = rs.getString("url"); // 選單 url
                temp[4] = rs.getString("srt"); // 選單編號
				result.add(temp);
			} else {
				String exact = rs.getString("staffSet"); // exact value.
				String fuzzy = rs.getString("orgSet"); // fuzzy value.
				// 檢查是否符合條件, 是的話 新增到 result 裡面.
				if (this.exactCheck(data, exact)
						|| (fuzzy == null && exact == null)
						|| (fuzzy != null && fuzzy.trim().length() != 0 && this
								.fuzzyCheck(data, fuzzy))) {
					String[] temp = new String[5];
					temp[0] = rs.getString("tsn"); // 選單 tsn
					temp[1] = rs.getString("ftsn"); // 父階選單 tsn
					temp[2] = rs.getString("nam"); // 選單名稱
					temp[3] = rs.getString("url"); // 選單 url
                    temp[4] = rs.getString("srt"); // 選單編號
					result.add(temp);
				}
			}
		}
		utils.cleanUp();
		return result;
	}

	/**
	 * 取得有權限的人員清單.
	 * 
	 * @param exact
	 *            String
	 * @param fuzzy
	 *            String
	 * @return List
	 * @throws Exception
	 */
	public List getAclList(String exact, String fuzzy) throws Exception {
		List<String[]> result = new ArrayList<String[]>();
		exact = (exact == null) ? "" : exact;
		fuzzy = (fuzzy == null) ? "" : fuzzy;
		List list = this.getAccountList();
		Iterator iter = list.iterator();
		while (iter.hasNext()) {
			String[] item = (String[]) iter.next();
			if (this.exactCheck(item, exact)
					|| (fuzzy.trim().length() != 0 && this.fuzzyCheck(item,
							fuzzy))) { // 檢查是否符合條件, 是的話 新增到 result 裡面.
				result.add(item);
			}
		}
		return result;
	}

	public boolean isAuthorized(String sysCode, String hrNum) throws Exception {
		// 1. 預設沒有權限.
		boolean result = false;
		// 2. 是否為超級使用者. 是 : true, 否 : 檢查是否有權限.
		if (this.isPowerUser(hrNum)) {
			result = true;
		} else {
			// 檢查 使用者 是否有 sysCode 的權限.
			Utils utils = new Utils(request);
			String sql = "select * from sys..sys002 where sysCode = ?";
			utils.prepareStatement("sqltest", sql);
			utils.setString(1, sysCode);
			ResultSet rs = utils.executeQuery();
			if (rs.next()) { // 檢查此 sysCode 賦予的權限.
				String exact = rs.getString("staffSet");
				String fuzzy = rs.getString("orgSet");
				String[] userData = this.getAccountData(hrNum);
				// 檢查此人員 是否符合 exact, fuzzy條件.
				result = this.exactCheck(userData, exact)
						|| (fuzzy.trim().length() != 0 && this.fuzzyCheck(
								userData, fuzzy));
			}
			utils.cleanUp();
		}
		return result;
	}
}
